package org.texteasy;

import java.util.HashMap;
import java.util.HashSet;

import org.texteasy.helpers.MessageEditorStates;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.res.Resources;
import android.database.CharArrayBuffer;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.provider.Contacts.People;
import android.telephony.gsm.SmsMessage;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnKeyListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ResourceCursorAdapter;
import android.widget.TextView;

public class MessageEditor extends Activity implements View.OnClickListener, TextWatcher {

	private static final String TAG = "MessageEditor";
	
	private final static int EDIT_CONTACTS_ID = Menu.FIRST;
	private final static int CANCEL_MESSAGE_ID = Menu.FIRST + 1;
	private static final int REMOVE_CONTACT_ID = Menu.FIRST + 2;
	
	public static final String CONTACT_IDS = "ContactIds";
	public static final String MESSAGE_EDITOR_STATE = "MessageEditorState";
	
	
	private String[] loadListItems = {"Loading Contacts..."};
	private MessageEditorStates state;
	
	private Button mSendButton;
	private TextView mEmbeddedTextEditor;
	private ListView mSelectionList;
	private ListView mLoadingList;
	private TextView mTextCounter;
	
	private HashSet<Long> contactIds;
	private String[] projection = new String[] {People._ID,People.NAME, People.TYPE, People.NUMBER};
	private int CHARS_BEFORE_COUNTER_SHOWN=130;
	private MessageService messageService;
	
	private BroadcastReceiver broadcastReceiver = new BroadcastReceiver(){
		public void onReceive(Context context, Intent intent) {
			
			int messageServiceEvent = intent.getExtras().getInt(TextEasyMessageService.MESSAGE_EVENT);
			
			if(messageServiceEvent == TextEasyMessageService.MESSAGE_ACCEPTED_EVENT){
				long messageId = intent.getExtras().getLong(TextEasyMessageService.MESSAGE_ID);
				handler.messageReceipt(messageId);
			}else if(messageServiceEvent == TextEasyMessageService.MESSAGE_SENT_EVENT){
				long messageId = intent.getExtras().getLong(TextEasyMessageService.MESSAGE_ID);
				long contactId = intent.getExtras().getLong(TextEasyMessageService.CONTACT_ID);
				
				Log.e(TAG, "recieved sent notification for message: " + messageId + " and contact: " + contactId);
				//TODO: sent event with these details, will check if message is for 
				//currently displayed info, if so then will re-query message contacts sent status
			}
			
			//removeMeMessagesSent = intent.getExtras().getInt(TextEasyMessageService.MESSAGE_SENT_NUMBER);
			//ContactItemListAdapter adaptor = (ContactItemListAdapter)listView.getAdapter();
			//adaptor.notifyDataSetChanged();
		};
	};
	
	private ServiceConnection serviceConnection = new ServiceConnection(){
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			
			messageService = MessageService.Stub.asInterface(service);
			
		}
		
		@Override
		public void onServiceDisconnected(ComponentName name) {
			
			messageService = null;
			
		}
	};
	
	private MessageEditorHandler handler = new MessageEditorHandler(this);
	
	
	private final OnKeyListener mEmbeddedTextEditorKeyListener =
        new OnKeyListener() {
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if ((event.getAction() == KeyEvent.ACTION_DOWN)
                        && (keyCode == KeyEvent.KEYCODE_ENTER)
                        && !event.isShiftPressed()) {
                    
                	Log.e(TAG, "Begin sending message");
                	handler.sendMessageEvent();
                	Log.e(TAG, "End sending message");
                    return true;
                } else {
                    return false;
                }
            }
        };
	
	private String getContactIdsInStatement(){
		StringBuffer buffer = new StringBuffer(" in(");
		
		HashSet<Long> contactIds = this.contactIds;
    	for(Long contactId: contactIds){
    		buffer.append(contactId).
				append(","); 
    	}
    	
    	return buffer.substring(0, buffer.length() - 1) + ")";
	}
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		setContentView(R.layout.message_editor);

		initializeResourceReferences();
		
		//setup the default state (INITIAL_STATE)
		ListView listView = mLoadingList;
		listView.setAdapter(new ArrayAdapter<String>(this, R.layout.loading_list_row, loadListItems));
		listView.setItemsCanFocus(false);
		
		state = MessageEditorStates.INITIAL_STATE;
    	mSendButton.setEnabled(false);
    	mEmbeddedTextEditor.setEnabled(false);
    	mEmbeddedTextEditor.addTextChangedListener(this);
    	
    	mSelectionList.setAdapter(null);
    	mSelectionList.setItemsCanFocus(false);
    	mSelectionList.setOnCreateContextMenuListener(this);
		
		if(getLastNonConfigurationInstance() == null){
			
			Bundle extras = getIntent().getExtras();
			
			HashMap<String, Object> data = new HashMap<String, Object>();
			for(String key:extras.keySet()){
				data.put(key, extras.get(key));
			}
			handler.initializeEvent(data);
		}else{
			
			HashMap<String, Object> data = (HashMap<String, Object>)getLastNonConfigurationInstance();
			handler.initializeEvent(data);
			
			/*Object[] previousState = (Object[])getLastNonConfigurationInstance();
			MessageEditorStates state = (MessageEditorStates)previousState[0];
			this.contactIds = (HashSet<Long>)previousState[1];
			if(state == MessageEditorStates.NEW_MESSAGE_LOADING){
				handler.enqueueStates(new MessageEditorStates[]{
					MessageEditorStates.NEW_MESSAGE_LOADING});
				handler.dequeueState();
			}else if(state == MessageEditorStates.NEW_MESSAGE_WITH_NO_TEXT){
				handler.enqueueStates(new MessageEditorStates[]{
					MessageEditorStates.NEW_MESSAGE_LOADING,
					MessageEditorStates.NEW_MESSAGE_WITH_NO_TEXT});
				handler.dequeueState();				
			}else if(state == MessageEditorStates.NEW_MESSAGE_WITH_TEXT){
				handler.enqueueStates(new MessageEditorStates[]{
					MessageEditorStates.NEW_MESSAGE_LOADING,
					MessageEditorStates.NEW_MESSAGE_WITH_NO_TEXT,
					MessageEditorStates.NEW_MESSAGE_WITH_TEXT});
				handler.dequeueState();
			}else{
				
			}
			*/
		}
		
		
		mSendButton.setOnClickListener(this);
		
		bindService(new Intent(this, TextEasyMessageService.class), serviceConnection, BIND_AUTO_CREATE);
	}
	
	private void initializeResourceReferences(){
		
		mSendButton = (Button)findViewById(R.id.send_button);
		mEmbeddedTextEditor = (TextView)findViewById(R.id.embedded_text_editor);
		mEmbeddedTextEditor.setOnKeyListener(mEmbeddedTextEditorKeyListener);
		mSelectionList = (ListView)findViewById(R.id.selectionList);
		mLoadingList = (ListView)findViewById(R.id.loadingMessageEditorList);
		mTextCounter = (TextView)findViewById(R.id.text_counter);
	}
	
	@Override
    protected void onPause() {
    	super.onPause();
    	unregisterReceiver(broadcastReceiver);
    	if(serviceConnection != null){
    		try{
    			unbindService(serviceConnection);
    		}catch(Exception ex){
    			Log.w(TAG, ex.getMessage());
    		}
    	}
    }
    
    @Override
    protected void onResume() {
    	super.onResume();
    	registerReceiver(broadcastReceiver, new IntentFilter(TextEasyMessageService.MESSAGE_SENT_BROADCAST));
    }
	
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    	super.onCreateOptionsMenu(menu);
    	menu.add(Menu.NONE, EDIT_CONTACTS_ID, 0, R.string.EDIT_MESSAGE_EDIT_CONTACTS);
    	menu.add(Menu.NONE, CANCEL_MESSAGE_ID, 0, R.string.EDIT_MESSAGE_CANCEL);
    	return true;
    }
    
    @Override
    public Object onRetainNonConfigurationInstance() {
    	
    	HashMap<String,Object> data = new HashMap<String, Object>();
    	data.put(MESSAGE_EDITOR_STATE, this.state.getName());
    	data.put(CONTACT_IDS, this.contactIds);
    	return data;
    }
    
    
    private void queryContactsAndRefreshUI(final Long messageId){
    	
    	Thread queryContacts = new Thread(new Runnable(){
    		@Override
    		public void run() {
    			Uri contacts = People.CONTENT_URI;
    			
    			final ContentResolver resolver = getContentResolver();
    			
				Cursor managedCursor = resolver.query(contacts, projection, 
					"PEOPLE." + People._ID + getContactIdsInStatement(), 
					null, People.DEFAULT_SORT_ORDER);
				
				handler.contactsQueryCompleteEvent(managedCursor);
    		}
    	});
    	queryContacts.start();
    }
    
    
    @Override
    public void onCreateContextMenu(ContextMenu menu, View v,
    		ContextMenuInfo menuInfo) {
    	//super.onCreateContextMenu(menu, v, menuInfo);
    	
    	AdapterView.AdapterContextMenuInfo info;
        try {
             info = (AdapterView.AdapterContextMenuInfo) menuInfo;
        } catch (ClassCastException e) {
            Log.e(TAG, "bad menuInfo", e);
            return;
        }
    	
        Cursor cursor = (Cursor)mSelectionList.getAdapter().getItem(info.position);
        if(cursor == null){
        	// For some reason the requested item isn't available, do nothing
        	return;
        }
        
    	menu.setHeaderTitle(cursor.getString(BulkMessenger.NAME_COLUMN_INDEX));
         
    	//Add a menu item to delete the note
    	menu.add(0, REMOVE_CONTACT_ID, 0, R.string.EDIT_MESAGE_REMOVE_CONTACT);
    }
    
    @Override
    public boolean onMenuItemSelected(int featureId, MenuItem item) {
    	
    	AdapterView.AdapterContextMenuInfo info = null;
    	
    	if(item.getMenuInfo() != null){
    	    try {
	             info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
	        } catch (ClassCastException e) {
	            Log.e(TAG, "bad menuInfo", e);
	            return false;
	        }
    	}
    	
    	long itemId = -1;
    	if(info ==null){
    		itemId = mSelectionList.getSelectedItemId();
    	}else{
    		itemId = info.id;
    	}
    	
    	switch(item.getItemId()) {
        	case REMOVE_CONTACT_ID:
        		handler.removeContactEvent(itemId);
	            return true;
        	case EDIT_CONTACTS_ID:
        		Intent dataToReturn = new Intent();
        		dataToReturn.putExtra(CONTACT_IDS, this.contactIds);
        		setResult(RESULT_OK, dataToReturn);
                finish();
        		return true;
        	case CANCEL_MESSAGE_ID:
        		setResult(RESULT_CANCELED);
                finish();
        		return true;
        }
    	
    	return super.onMenuItemSelected(featureId, item);
    }
    
    @Override
    public void onClick(View v) {
    	handler.sendMessageEvent();
    }
    
    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {}
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count,int after) {}
    @Override
    public void afterTextChanged(Editable s) {
    	
    	handler.textChangedEvent();
    }
    
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
    	
    	if(keyCode == KeyEvent.KEYCODE_BACK){
    		Intent dataToReturn = new Intent();
    		dataToReturn.putExtra(CONTACT_IDS, this.contactIds);
    		setResult(RESULT_OK, dataToReturn);
            finish();
    	}
    	
    	return super.onKeyDown(keyCode, event);
    }
    
    final static class ContactListItemCache {
    	public TextView nameView;
        public CharArrayBuffer nameBuffer = new CharArrayBuffer(128);
        public TextView labelView;
        public CharArrayBuffer labelBuffer = new CharArrayBuffer(128);
        public TextView numberView;
        public CharArrayBuffer numberBuffer = new CharArrayBuffer(128);
        public ImageView imageView;
    }
    
    private final class ContactItemListAdapter extends ResourceCursorAdapter{
    	private CharSequence[] mLocalizedLabels;
    	private CharSequence mUnknownNameText;
    	
    	public ContactItemListAdapter(Context context, int resource, Cursor cursor){
    		super(context, resource, cursor);
    		
    		final Resources resources = context.getResources();
    		mLocalizedLabels = resources.getStringArray(android.R.array.phoneTypes);
    		
    		mUnknownNameText = context.getText(android.R.string.unknownName);
    	}
    	
    	@Override
    	public View newView(Context context, Cursor cursor, ViewGroup parent) {
    		final View view = super.newView(context, cursor, parent);

            final ContactListItemCache cache = new ContactListItemCache();
            cache.nameView = (TextView) view.findViewById(R.id.selectedName);
            cache.labelView = (TextView) view.findViewById(R.id.selectedLabel);
            cache.labelView.setCompoundDrawablePadding(3);
            cache.numberView = (TextView) view.findViewById(R.id.selectedPhoneNumber);
            cache.imageView = (ImageView)view.findViewById(R.id.messageSent);
            view.setTag(cache);

            return view;
    		
    	}
    	
    	 /*@Override
         public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
    		 return doFilter(constraint.toString());
         }*/
    	
    	@Override
		public void bindView(View view, Context context, Cursor cursor) {
			
			final ContactListItemCache cache = (ContactListItemCache) view.getTag();
			
			// Set the name           
            cursor.copyStringToBuffer(BulkMessenger.NAME_COLUMN_INDEX, cache.nameBuffer);
            int size = cache.nameBuffer.sizeCopied;
            if (size != 0) {
                cache.nameView.setText(cache.nameBuffer.data, 0, size);
            } else {
                cache.nameView.setText(mUnknownNameText);
            }
            
            //Set the phone number
            TextView numberView = cache.numberView;
            cursor.copyStringToBuffer(BulkMessenger.NUMBER_COLUMN_INDEX, cache.numberBuffer);
            size = cache.numberBuffer.sizeCopied;
            if (size != 0) {
                numberView.setText(cache.numberBuffer.data, 0, size);
                numberView.setVisibility(View.VISIBLE);
            } else {
                numberView.setVisibility(View.GONE);
            }
            
            // Set the label
            TextView labelView = cache.labelView;
            if (!cursor.isNull(BulkMessenger.TYPE_COLUMN_INDEX)) {
                int type = cursor.getInt(BulkMessenger.TYPE_COLUMN_INDEX);

                if (type != People.Phones.TYPE_CUSTOM) {
                    try {
                        labelView.setText(mLocalizedLabels[type - 1]);
                    } catch (ArrayIndexOutOfBoundsException e) {
                        labelView.setText(mLocalizedLabels[People.Phones.TYPE_HOME - 1]);
                    }
                } else {
                	// Set the text to a length of 0
                    labelView.setText(cache.labelBuffer.data, 0, 0);
                }
            } else {
                // Set the text to a length of 0
                labelView.setText(cache.labelBuffer.data, 0, 0);
            }
            
			cache.imageView.setVisibility(ImageView.INVISIBLE);
		}
    }
    
    private final class MessageEditorHandler extends Handler{
    	
    	private static final int EVENT_INITIALIZE=1;
    	private static final int EVENT_CONTACTS_QUERY_COMPLETE=2;
    	private static final int EVENT_MESSAGE_TEXT_CHANAGED=3;
    	private static final int EVENT_REMOVE_CONTACT=4;
    	private static final int EVENT_SEND_MESSAGE=5;
    	private static final int EVENT_RECEIVED_SERVICE_RECEIPT=6;
    	
    	
    	private MessageEditor that;
    	private Long messageId;
		
		public MessageEditorHandler(MessageEditor messageEditor){
			that = messageEditor;
		}
		
		public void handleMessage(Message msg) {
			
			boolean eventHandled = false;
			if(state == MessageEditorStates.INITIAL_STATE){
				eventHandled = initialState(msg);
			}else if(state == MessageEditorStates.NEW_MESSAGE_LOADING){
				eventHandled = newMessageLoadingState(msg);
			}else if(state == MessageEditorStates.NEW_MESSAGE_WITH_NO_TEXT){
				eventHandled = newMessageNoTextState(msg);
			}else if(state == MessageEditorStates.NEW_MESSAGE_WITH_TEXT){
				eventHandled = newMessageWtihTextState(msg);
			}else if(state == MessageEditorStates.PAUSED_NEW_MESSAGE_WITH_TEXT){
				eventHandled = pausedNewMessageWtihTextState(msg);
			}else if(state == MessageEditorStates.WAITING_FOR_SERVICE_RECEIPT){
				eventHandled = waitingForServiceReceipt(msg);
			}else if(state == MessageEditorStates.PAUSED_WAITING_FOR_SERVICE_RECEIPT){
				eventHandled = pausedWaitingForServiceReceipt(msg);
			}else{
				throw new IllegalStateException("State not currently supported");
			}
			
			if(!eventHandled){
				Log.i(TAG, "Unhandled event: " + msg.arg1 + " in state: " + state.getName());
			}
		};
		
		public void initializeEvent(HashMap<String, Object> initialState){
			Message message = obtainMessage();
			message.arg1 = EVENT_INITIALIZE;
			message.obj = initialState;
			sendMessage(message);
		}
		
		public void contactsQueryCompleteEvent(Cursor cursor){
			Message message = obtainMessage();
			message.arg1 = EVENT_CONTACTS_QUERY_COMPLETE;
			message.obj = cursor;
			sendMessage(message);
		}
		
		public void textChangedEvent(){
			Message message = obtainMessage();
			message.arg1 = EVENT_MESSAGE_TEXT_CHANAGED;
			sendMessage(message);
		}
		
		public void removeContactEvent(Long contactId){
			Message message = obtainMessage();
			message.arg1 = EVENT_REMOVE_CONTACT;
			message.obj = contactId;
			sendMessage(message);
		}
		
		public void sendMessageEvent(){
			Message message = obtainMessage();
			message.arg1 = EVENT_SEND_MESSAGE;
			sendMessage(message);
		}
		
		public void messageReceipt(long messageId){
			
			Message message = obtainMessage();
			message.arg1 = EVENT_RECEIVED_SERVICE_RECEIPT;
			message.obj = messageId;
			sendMessage(message);
			
		}
		
		private void transitionToState(MessageEditorStates state){
			
			//Dont think will ever need to transition into NEW_MESSAGE_LOADING from
			//any state except the initial state
			if(state == MessageEditorStates.NEW_MESSAGE_LOADING || 
				state == MessageEditorStates.PAUSED_NEW_MESSAGE_WITH_TEXT ||
				state == MessageEditorStates.PAUSED_WAITING_FOR_SERVICE_RECEIPT){
				
				mSendButton.setEnabled(false);
		    	mEmbeddedTextEditor.setEnabled(false);
		    	mEmbeddedTextEditor.addTextChangedListener(that);
		    	
		    	mSelectionList.setAdapter(null);
		    	mSelectionList.setItemsCanFocus(false);
		    	mSelectionList.setOnCreateContextMenuListener(that);
				
			}else if(state == MessageEditorStates.NEW_MESSAGE_WITH_NO_TEXT){
		    	mSendButton.setEnabled(false);
		    	mEmbeddedTextEditor.setEnabled(true);
		    	mEmbeddedTextEditor.requestFocus();
		    	
		    	if(mTextCounter.getVisibility() == View.VISIBLE){
	    			mTextCounter.setVisibility(View.GONE);
	    		}
		    	
			}else if(state == MessageEditorStates.NEW_MESSAGE_WITH_TEXT){
		    	mSendButton.setEnabled(true);
		    	mEmbeddedTextEditor.setEnabled(true);
			}else if(state == MessageEditorStates.WAITING_FOR_SERVICE_RECEIPT){
				mSendButton.setEnabled(false);
		    	mEmbeddedTextEditor.setEnabled(false);
			}else{
				throw new IllegalStateException("Unsupported");
			}
			that.state = state;
		}
		
		private boolean initialState(Message message){
			
			if(message.arg1 == EVENT_INITIALIZE){
				
				HashMap<String, Object> bundle = (HashMap<String, Object>)message.obj;
				
				MessageEditorStates state = MessageEditorStates.getMessageEditorStateFromName(
						(String)bundle.get(MESSAGE_EDITOR_STATE));
				
				if(state == MessageEditorStates.NEW_MESSAGE_LOADING || 
					state == MessageEditorStates.NEW_MESSAGE_WITH_NO_TEXT){
					//transition to NEW_MESSAGE_LAODING
					contactIds = (HashSet<Long>)bundle.get(CONTACT_IDS);
					
					transitionToState(MessageEditorStates.NEW_MESSAGE_LOADING);
			    	queryContactsAndRefreshUI(null);
				}else if(state == MessageEditorStates.NEW_MESSAGE_WITH_TEXT){
					
					contactIds = (HashSet<Long>)bundle.get(CONTACT_IDS);
					
					transitionToState(MessageEditorStates.PAUSED_NEW_MESSAGE_WITH_TEXT);
			    	queryContactsAndRefreshUI(null);
				}else if(state == MessageEditorStates.WAITING_FOR_SERVICE_RECEIPT){
					contactIds = (HashSet<Long>)bundle.get(CONTACT_IDS);
					
					transitionToState(MessageEditorStates.PAUSED_WAITING_FOR_SERVICE_RECEIPT);
			    	queryContactsAndRefreshUI(null);
				}else{
					throw new IllegalStateException("Unsupported transition");
				}
				
				return true;
			}
			
			return false;
		}
		
		private boolean newMessageLoadingState(Message message){
			
			if(message.arg1 == EVENT_CONTACTS_QUERY_COMPLETE){
				
				//Transition to NewMessageWithNoText
				displayUpdatedContacts((Cursor)message.obj);
				mLoadingList.setVisibility(View.GONE);
				mSelectionList.setVisibility(View.VISIBLE);
				
				transitionToState(MessageEditorStates.NEW_MESSAGE_WITH_NO_TEXT);
				return true;
			}
			
			return false;
	    }
		
		private boolean newMessageNoTextState(Message message){
			
			if(message.arg1 == EVENT_MESSAGE_TEXT_CHANAGED){
				
				String messageBody = mEmbeddedTextEditor.getText().toString();
				int[] messageLengthResults = SmsMessage.calculateLength(messageBody, true);
				
				if(messageLengthResults[1] >0){
					transitionToState(MessageEditorStates.NEW_MESSAGE_WITH_TEXT);
				}
				
				//if someone copyies in a large message then will need to 
				//update the textCounter so just let the NEW_MESSAGE_WITH_TEXT
				//handle it
				if(messageLengthResults[1] >= CHARS_BEFORE_COUNTER_SHOWN){
					this.textChangedEvent();
				}
				
				return true;
			}else if(message.arg1 == EVENT_REMOVE_CONTACT){
				removeContact((Long)message.obj);
				return true;
			}else if(message.arg1 == EVENT_CONTACTS_QUERY_COMPLETE){
				displayUpdatedContacts((Cursor)message.obj);
				return true;
			}
	    	
	    	return false;
	    }
		
		private boolean newMessageWtihTextState(Message message){
	    	
			if(message.arg1 == EVENT_MESSAGE_TEXT_CHANAGED){
				
				String messageBody = mEmbeddedTextEditor.getText().toString();
				int[] messageLengthResults = SmsMessage.calculateLength(messageBody, true);
				
				if(messageLengthResults[1] >= CHARS_BEFORE_COUNTER_SHOWN){
					
					TextView textCounter = mTextCounter;
		    		
		    		int remainingInCurrentMessage;
		    		int messageCount = 0;
		            if (messageLengthResults[1] > SmsMessage.MAX_USER_DATA_SEPTETS) {
		                // If we have more characters than will fit in one SMS, we need to factor
		                // in the size of the header to determine how many will fit.
		            	messageCount = messageLengthResults[1] / (SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER) + 1;
		                remainingInCurrentMessage = SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER
		                                            - (messageLengthResults[1] % SmsMessage.MAX_USER_DATA_SEPTETS_WITH_HEADER);
		            } else {
		            	messageCount = 1;
		                remainingInCurrentMessage = SmsMessage.MAX_USER_DATA_SEPTETS - messageLengthResults[1];
		            }
		    		
		    		textCounter.setText(remainingInCurrentMessage + " / " + messageCount);
		    		
		    		 
		    		if(textCounter.getVisibility() != View.VISIBLE){
		    			textCounter.setVisibility(View.VISIBLE);
		    		}
		    		
					
				}else if(messageLengthResults[1] < CHARS_BEFORE_COUNTER_SHOWN && messageLengthResults[1] > 0){
					if(mTextCounter.getVisibility() == View.VISIBLE){
		    			mTextCounter.setVisibility(View.GONE);
		    		}
				}else if(messageLengthResults[1] == 0){
					transitionToState(MessageEditorStates.NEW_MESSAGE_WITH_NO_TEXT);
				}
				
				return true;
			}else if(message.arg1 == EVENT_REMOVE_CONTACT){
				removeContact((Long)message.obj);
				return true;
			}else if(message.arg1 == EVENT_CONTACTS_QUERY_COMPLETE){
				displayUpdatedContacts((Cursor)message.obj);
				return true;
			}else if(message.arg1 == EVENT_SEND_MESSAGE){
				
				HashSet<Long> contactIds = that.contactIds;
				long[] contactIdsToSend = new long[contactIds.size()];
				int i=0;
				for(Long contactId:contactIds ){
					contactIdsToSend[i] = contactId;
					i++;
				}
				
				try{
		    		messageService.sendMessage(contactIdsToSend, 
		    				mEmbeddedTextEditor.getText().toString());
		    	}catch(RemoteException ex){
		    		Log.e(TAG, ex.getMessage());
		    		throw new RuntimeException(ex);
		    	}
				
		    	transitionToState(MessageEditorStates.WAITING_FOR_SERVICE_RECEIPT);
		    	
		    	return true;
			}
			
	    	return false;
	    }
    	
		private boolean pausedNewMessageWtihTextState(Message message){
			
			if(message.arg1 == EVENT_CONTACTS_QUERY_COMPLETE){
				
				displayUpdatedContacts((Cursor)message.obj);
				mLoadingList.setVisibility(View.GONE);
				mSelectionList.setVisibility(View.VISIBLE);
				transitionToState(MessageEditorStates.NEW_MESSAGE_WITH_TEXT);
				this.textChangedEvent();
				
				return true;
			}
			
			return false;
		}
		
		private boolean pausedWaitingForServiceReceipt(Message message){
			
			if(message.arg1 == EVENT_CONTACTS_QUERY_COMPLETE){
				
				displayUpdatedContacts((Cursor)message.obj);
				mLoadingList.setVisibility(View.GONE);
				mSelectionList.setVisibility(View.VISIBLE);
				transitionToState(MessageEditorStates.WAITING_FOR_SERVICE_RECEIPT);
				
				return true;
			}
			
			return false;
		}
		
		private boolean waitingForServiceReceipt(Message message){
			
			if(message.arg1 == EVENT_RECEIVED_SERVICE_RECEIPT){
				
				messageId = (Long)message.obj;
				queryContactsAndRefreshUI(messageId);
				transitionToState(MessageEditorStates.IN_PROGRESS_MESSSAGE);
			}
			
			return false;
		}
		
		private void displayUpdatedContacts(Cursor cursor){
	    	
	    	ListView contactListView = mSelectionList;
	    	if(contactListView.getAdapter() == null){
	    		//first time we got a cursor
	    		ResourceCursorAdapter contactsAdaptor = new ContactItemListAdapter(that, 
	    	    		R.layout.selection_list,cursor);
	    		contactListView.setAdapter(contactsAdaptor);
	    	}else{
	    		ResourceCursorAdapter contactsAdaptor = (ResourceCursorAdapter)
	    			contactListView.getAdapter();
	    		contactsAdaptor.changeCursor(cursor);
	    	}
	    }
		
		private void removeContact(long itemId){
	    	
    		HashSet<Long> contactIds = that.contactIds;
    		if(contactIds.contains(itemId)){
    			contactIds.remove(itemId);
    			if(contactIds.isEmpty()){
    				setResult(RESULT_CANCELED);
                    finish();
    			}else{
    				queryContactsAndRefreshUI(null);
    			}
    		}else{
    			Log.e(TAG, "unknow contactId: " + itemId);
    		}
		}
    }
    
    /*
     * 
    	
    }
     */
    
	/*private final class ContactItemListAdapter extends ArrayAdapter<String>{
		
		private Activity context;
		
		public ContactItemListAdapter(Activity context) {
			
			super(context, R.layout.selection_list, names);
			
			this.context = context;
		}
		
		
		
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			
			View row = convertView;
			
			if(row == null){
				LayoutInflater inflater = context.getLayoutInflater();
				row = inflater.inflate(R.layout.selection_list, null);
			}
			
			TextView name = (TextView)row.findViewById(R.id.selectedName);
			name.setText(names[position]);
			
			TextView number = (TextView)row.findViewById(R.id.selectedPhoneNumber);
			number.setText(numbers[position]);
			
			TextView label = (TextView)row.findViewById(R.id.selectedLabel);
			label.setText(labels[position]);
			
			ImageView imageView = (ImageView)row.findViewById(R.id.messageSent);
			if(position < removeMeMessagesSent){
				imageView.setVisibility(ImageView.VISIBLE);
			}else{
				imageView.setVisibility(ImageView.INVISIBLE);
			}
			return row;
		}
		
	}
	*/
}
